﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using Noris.Tools.FrxEditor.Components;
using Noris.Tools.FrxEditor.ComponentsLayer;
using Noris.Schedule.Support;
using Noris.Tools.FrxEditor.Data;

namespace Noris.Tools.FrxEditor.Editor
{
	/// <summary>
	/// EditorSplitter : třída, která představuje vizuální splitter (oddělovač dvou sousedních prostorů)
	/// </summary>
	public class EditorSplitter : EditorItem
	{
		#region Konstrukce
		/// <summary>
		/// Konstruktor
		/// </summary>
		public EditorSplitter()
		{
			this._SplitterOrientation = Orientation.Horizontal;
		}
		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="orientation"></param>
		public EditorSplitter(Orientation orientation)
		{
			this._SplitterOrientation = orientation;
		}
		#endregion
		#region Vizuální vlastnosti splitteru (orientace, pozice, velikost)
		/// <summary>
		/// Orientace splitteru
		/// </summary>
		[Browsable(false)]
		public Orientation SplitterOrientation
		{
			get { return this._SplitterOrientation; }
			set { this._SplitterOrientation = value; }
		}
		/// <summary>
		/// Pozice splitteru v tom směru, v němž je posouván:
		/// pro SplitterOrientation = Horizontal (vodorovná čára) je SplitterPosition = souřadnice Y;
		/// pro SplitterOrientation = Vertical (svislá čára) je SplitterPosition = souřadnice X;
		/// </summary>
		[Browsable(false)]
		public float SplitterPosition
		{
			get { return this._Position; }
            set { this._Position = value; this._AccomodatePosition(); }
		}
		/// <summary>
		/// Nejmenší pozice splitteru v tom směru, v němž je posouván.
		/// </summary>
		[Browsable(false)]
        public float SplitterPositionMin
		{
            get { return this._SplitterPositionMin; }
            set { this._SplitterPositionMin = value; this._AccomodatePosition(); }
		}
        /// <summary>
        /// Největší pozice splitteru v tom směru, v němž je posouván.
        /// </summary>
        [Browsable(false)]
        public float SplitterPositionMax
        {
            get { return this._SplitterPositionMax; }
            set { this._SplitterPositionMax = value; this._AccomodatePosition(); }
        }
        /// <summary>
        /// Koriguje _SplitterPositionMax a _Position
        /// </summary>
        private void _AccomodatePosition()
        {
            if (this._SplitterPositionMax < this._SplitterPositionMin)
                this._SplitterPositionMax = this._SplitterPositionMin;
            if (this._Position < this._SplitterPositionMin)
                this._Position = this._SplitterPositionMin;
            if (this._Position > this._SplitterPositionMax)
                this._Position = this._SplitterPositionMax;
        }
		/// <summary>
		/// Tloušťka (síla) splitteru = počet pixelů na šířku
		/// </summary>
		[Browsable(false)]
		public float SplitterWeight
		{
			get { return this._Weight; }
			set { this._Weight = (value <= 0f ? 0f : value); }
		}
		/// <summary>
		/// Počátek splitteru (souřadnice Left při orientaci Horizontal; souřadnice Top při orientaci Vertical)
		/// </summary>
		[Browsable(false)]
		public float SplitterBegin
		{
			get { return this._Begin; }
			set { this._Begin = value; }
		}
		/// <summary>
		/// Délka splitteru = počet pixelů na délku (hodnota Width při orientaci Horizontal; hodnota Height při orientaci Vertical)
		/// </summary>
		[Browsable(false)]
		public float SplitterLength
		{
			get { return this._Length; }
			set { this._Length = (value <= 0f ? 0f : value); }
		}
		/// <summary>
		/// Konec splitteru (souřadnice Right při orientaci Horizontal; souřadnice Bottom při orientaci Vertical)
		/// </summary>
		[Browsable(false)]
		public float SplitterEnd
		{
			get { return this._Begin + this._Length; }
			set { this._Length = (value <= this._Begin ? 0f : value - this._Begin); }
		}
		/// <summary>
		/// Středový bod.
		/// Při setování se akceptuje pouze pohyblivá dimenze (nelze přemístit Splitter jinam než v pohyblivém směru).
		/// </summary>
		[Browsable(false)]
		public PointF PivotPoint
		{
			get
			{
				switch (this._SplitterOrientation)
				{
					case Orientation.Horizontal:
						return new PointF(this._Begin + this._Length / 2f, this._Position);
					case Orientation.Vertical:
						return new PointF(this._Position, this._Begin + this._Length / 2f);
				}
				return PointF.Empty;
			}
			set
			{
				switch (this._SplitterOrientation)
				{
					case Orientation.Horizontal:
                        this.SplitterPosition = value.Y;
						break;
					case Orientation.Vertical:
						this.SplitterPosition = value.X;
						break;
				}
			}
		}
		/// <summary>
		/// Typ kurzoru, odpovídajícího orientaci splitteru
		/// </summary>
		[Browsable(false)]
		public SysCursorType CursorType
		{
			get
			{
				switch (this._SplitterOrientation)
				{
					case Orientation.Horizontal:
						return SysCursorType.HSplit;
					case Orientation.Vertical:
						return SysCursorType.VSplit;
				}
				return SysCursorType.Default;
			}
		}
		/// <summary>
		/// Souřadnice splitteru.
		/// Při setování se akceptují všechny hodnoty, 
		/// přičemž SplitterWeight se nastavuje pouze tehdy, pokud je odpovídající rozměr větší než 0f.
		/// Pokud při setování nechceme řešit SplitterWeight a posunutí SplitterPosition o polovinu SplitterWeight, zadáme šířku/výšku == 0f.
		/// </summary>
		[Browsable(false)]
		public RectangleF SplitterBounds
		{
			get { return this.GetRealVisualBounds(); }
			set { this.SetRealVisualBounds(value, true); }
		}
		private Orientation _SplitterOrientation;
		/// <summary>
		/// Fyzické vizuální rozměry splitteru, tak jak je kreslen v controlu.
		/// Čtení vždy sestaví aktuální souřadnice ze souřadnic virtuálních (this._VirtualSplitter).
		/// Zápis uloží data do souřadnic virtuálních.
		/// </summary>
		protected RectangleF VisualBounds
		{
			get { return this.GetRealVisualBounds(); }
			set { this.SetRealVisualBounds(value, false); }
		}
		/// <summary>
		/// Vrátí reálné vizuální souřadnice na základě primárních dat
		/// </summary>
		/// <returns></returns>
		protected RectangleF GetRealVisualBounds()
		{	// Z virtuálních souřadnic vytvořím souřadnice vizuální:
			float w2 = this._Weight / 2;
			switch (this._SplitterOrientation)
			{
				case Orientation.Horizontal:
					return new RectangleF(this._Begin, this._Position - w2, this._Length, this._Weight);
				case Orientation.Vertical:
					return new RectangleF(this._Position - w2, this._Begin, this._Weight, this._Length);
			}
			return RectangleF.Empty;
		}
		/// <summary>
		/// Nastaví do svých primárních dat hodnoty z předané reálné vizuální souřadnice.
		/// Volitelně (podle ignoreZeroWeight) nenastavuje _Weight, pokud je odpovídající rozměr == 0f.
		/// </summary>
		/// <param name="real">Souřadnice reálného splitteru</param>
		/// <param name="ignoreZeroWeight">true: pokud je rozměr odpovídající Weight == 0, pak neměnit hodnotu Weight.</param>
		protected void SetRealVisualBounds(RectangleF real, bool ignoreZeroWeight)
		{	// Z vizuálních souřadnic (value) vytvořím souřadnice virtuální:
			float w2;
			switch (this._SplitterOrientation)
			{
				case Orientation.Horizontal:
					w2 = real.Height / 2f;
					this._Begin = real.X;
					this._Length = real.Width;
                    this.SplitterPosition = real.Y + w2;
					if (!ignoreZeroWeight || real.Height > 0f)
						this._Weight = real.Height;
					break;
				case Orientation.Vertical:
					w2 = real.Width / 2f;
					this._Begin = real.Y;
					this._Length = real.Height;
                    this.SplitterPosition = real.X + w2;
					if (!ignoreZeroWeight || real.Width > 0f)
						this._Weight = real.Width;
					break;
			}
		}
		private float _Position;
        private float _SplitterPositionMin = 5f;
        private float _SplitterPositionMax = 1000f;
		private float _Weight;
		private float _Begin;
		private float _Length;
		#endregion
		#region Eventy
		/// <summary>
		/// Událost, kdy se mění pozice splitteru
		/// </summary>
		public event EventHandler SplitterMoving;
		/// <summary>
		/// Vyvolá event SplitterMoving
		/// </summary>
		protected virtual void OnSplitterMoving()
		{
			if (this.SplitterMoving != null)
				this.SplitterMoving(this, EventArgs.Empty);
		}
		#endregion
		#region Kreslení
		/// <summary>
		/// Vrací vizuální souřadnice splitteru
		/// </summary>
		/// <param name="args"></param>
		/// <returns></returns>
        protected override RectangleF GetVisualBound(EditEventArgs args)
		{
			return this.VisualBounds;
		}
		/// <summary>
		/// Akceptuje do sebe nové vizuální souřadnice
		/// </summary>
		/// <param name="args"></param>
		/// <param name="visualBound"></param>
        protected override void SetVisualBound(EditEventArgs args, RectangleF visualBound)
		{
            base.SetVisualBound(args, visualBound);
			this.VisualBounds = visualBound;
		}
		/// <summary>
		/// Připraví intraktivní segmenty
		/// </summary>
		/// <param name="args"></param>
		protected override void PrepareSegments(EditPaintEventArgs args)
		{
            this.AllSegmentList = new List<EditorItemSegment>();

			bool isHor = (this._SplitterOrientation == Orientation.Horizontal);
			bool isVer = (this._SplitterOrientation == Orientation.Vertical);
			RectangleF bound = this.GetRealVisualBounds();
			SysCursorType cursorType = this.CursorType;
            this.PrepareSegmentAddOne(this, EditorItemSegmentGripType.Body,
                new RectangleF(bound.X - 1f, bound.Y - 1f, bound.Width + 2f, bound.Height + 2f),
                this.PivotPoint,
                bound,
                cursorType, cursorType, cursorType,
                EditorItemSegmentGripType.Body,
                isVer, isHor, false, false, false,
                EditMouseChangeType.EnterLeave | EditMouseChangeType.LeftClick | EditMouseChangeType.LeftDrag,
                args);
		}
		/// <summary>
		/// Vykreslí tělo splitteru
		/// </summary>
		/// <param name="args"></param>
		protected override void DrawBackground(EditPaintEventArgs args)
		{
            Steward.Diagnostic.InfoAddLineWithTime(" EditorSplitter.DrawBackground(MouseState=%0, Position=%1)", this.CurrentMouseState, this.SplitterPosition);

            // Kreslím tři obdélníky: 
            //  areaBR: dospodu ten, který se tváří jako pravý dolní okraj: ten je přes celou plochu
            //  na něj ten, který představuje horní a levý okraj, ten má počátek vlevo nahoře ale je o kousek menší,
            //  a navrch obdélník který představuje vnitřek:
            float w = 1f;
			RectangleF areaBR = this.VisualBounds;
            RectangleF areaTL = new RectangleF(areaBR.Location, new SizeF(areaBR.Width - w, areaBR.Height - w));
			RectangleF areaIN = new RectangleF(areaBR.X + w, areaBR.Y + w, areaBR.Width - 2 * w, areaBR.Height - 2 * w);

            Color colorBR = SystemColors.ControlDarkDark;
            Color colorTL = SystemColors.ControlLightLight;
            Color colorIN = SystemColors.Control;

            EditMouseState state = this.CurrentMouseState;
			if (state == EditMouseState.OnControl)
            {   // Stav s myší: jen se zbarví vnitřek
                colorIN = Color.YellowGreen;
            }
            else if (state == EditMouseState.MouseLeftDown || state == EditMouseState.MouseDragMove || state == EditMouseState.MouseDragResize)
			{   // Stav se zmáčknutou myší: otočí se barvy okrajů:
                Color color = colorBR;
                colorBR = colorTL;
                colorTL = color;
                colorIN = Color.GreenYellow;
            }

            using (SolidBrush brush = new SolidBrush(colorBR))
            {
                brush.Color = colorBR;
                args.Graphics.FillRectangle(brush, areaBR);
                brush.Color = colorTL;
                args.Graphics.FillRectangle(brush, areaTL);
                brush.Color = colorIN;
                args.Graphics.FillRectangle(brush, areaIN);
            }
		}
		/// <summary>
        /// V průběhu přesouvání volám event SplitterMoving
		/// </summary>
		/// <param name="args"></param>
		protected override void OnSegmentMouseLeftDragMove(EditInteractiveEventArgs args)
		{
            Steward.Diagnostic.InfoAddLineWithTime(" EditorSplitter.OnSegmentMouseLeftDragMove(Position=%0)", this.SplitterPosition);
            this.SetVisualBound(args, this.EditedCurrentVisualArea.Value);
            this.OnSplitterMoving();
		}
		#endregion
	}
}
